/*
 * 分布式唯一ID生成器
 */

package idgen

import (
	"errors"
	"gitee.com/zackeus/go-boot/idgen/internal"
	"gitee.com/zackeus/go-boot/idgen/store"
	"strconv"
	"time"
)

var (
	unAvailableErr = errors.New("the id store not available")
)

type (
	// Option 可选项
	Option func(o *internal.IdGeneratorOptions)
	// InitStoreFuc store 初始化函数
	InitStoreFuc func(maxWorkerId uint16) (store.IdStore, error)

	idGenerator struct {
		generator internal.IIdGenerator
		store     store.IdStore
	}
)

func New(f InitStoreFuc, opts ...Option) (IdGenerator, error) {
	o := internal.NewIdGeneratorOptions(0)
	for _, opt := range opts {
		opt(o)
	}

	/* 计算 workId 最大值 */
	maxWorkerIdNumber := uint16(1<<o.WorkerIdBitLength) - 1
	if maxWorkerIdNumber == 0 {
		maxWorkerIdNumber = 63
	}
	if o.WorkerId < 0 || o.WorkerId > maxWorkerIdNumber {
		return nil, errors.New("WorkerId error. (range:[0, " + strconv.FormatUint(uint64(maxWorkerIdNumber), 10) + "]")
	}

	s, err := f(maxWorkerIdNumber)
	if err != nil {
		return nil, err
	}
	/* 获取 workId */
	o.WorkerId = s.GetWorkerId()

	generator, err := internal.NewDefaultIdGenerator(o)
	if err != nil {
		return nil, err
	}
	return &idGenerator{
		generator: generator,
		store:     s,
	}, nil
}

func (i *idGenerator) Available() bool {
	return i.store.Available()
}

func (i *idGenerator) NextId() (uint64, error) {
	if !i.Available() {
		return 0, unAvailableErr
	}
	return uint64(i.generator.NextId()), nil
}

func (i *idGenerator) ExtractTime(id uint64) time.Time {
	return i.generator.ExtractTime(int64(id))
}

func (i *idGenerator) Shutdown(g ...bool) {
	if g == nil || !g[0] {
		i.store.Shutdown(false)
		return
	}
	i.store.Shutdown(true)
}

// WithMethod 雪花计算方法,（1-漂移算法|2-传统算法
func WithMethod(m uint16) Option {
	return func(o *internal.IdGeneratorOptions) {
		o.Method = m
	}
}

// WithBaseTime 基础时间（ms单位），不能超过当前系统时间
func WithBaseTime(t int64) Option {
	return func(o *internal.IdGeneratorOptions) {
		o.BaseTime = t
	}
}

// WithWorkerIdBitLength 机器码位长，默认值6，取值范围 [1, 15]（要求：序列数位长+机器码位长不超过22）
func WithWorkerIdBitLength(l byte) Option {
	return func(o *internal.IdGeneratorOptions) {
		o.WorkerIdBitLength = l
	}
}

// WithSeqBitLength 序列数位长，默认值6，取值范围 [3, 21]（要求：序列数位长+机器码位长不超过22）
func WithSeqBitLength(l byte) Option {
	return func(o *internal.IdGeneratorOptions) {
		o.SeqBitLength = l
	}
}

// WithMaxSeqNumber 最大序列数（含），设置范围 [MinSeqNumber, 2^SeqBitLength-1]，默认值0，表示最大序列数取最大值（2^SeqBitLength-1]）
func WithMaxSeqNumber(n uint32) Option {
	return func(o *internal.IdGeneratorOptions) {
		o.MaxSeqNumber = n
	}
}

// WithMinSeqNumber 最小序列数（含），默认值5，取值范围 [5, MaxSeqNumber]，每毫秒的前5个序列数对应编号0-4是保留位，其中1-4是时间回拨相应预留位，0是手工新值预留位
func WithMinSeqNumber(n uint32) Option {
	return func(o *internal.IdGeneratorOptions) {
		o.MinSeqNumber = n
	}
}

// WithTopOverCostCount 最大漂移次数（含），默认2000，推荐范围500-10000（与计算能力有关）
func WithTopOverCostCount(n uint32) Option {
	return func(o *internal.IdGeneratorOptions) {
		o.TopOverCostCount = n
	}
}
